/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package picshareservertest;

import com.swe622.rmi.server.fileserver.gui.ServerGUI;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.ServerError;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import shared.FileInfo;
import shared.PicRegistry;
import shared.ServerInfo;
import tcpserver.ConnectionManager;
import tcpserver.ServerEvent;

/**
 *
 * @author eric
 */
public class ServerControl implements ServerConfigurationManagerListener {

    private ServerConfiguration serverConfig;
    private ConnectionManager tcpConnectionManager;
    private ServerGUI monitor;
    private Thread connectionListenerThread;
    private final List<File> hostedFileList;
    private List<ServerListener> listeners;
    private ServerInfo serverInfo;
    private PicRegistry picRegistry;
   

    public ServerControl()
    {
     
        listeners = new ArrayList<ServerListener>();
        monitor = new ServerGUI();
        monitor.setVisible(false);
        hostedFileList = new ArrayList<File>();
        listeners.add(monitor);
        serverInfo = new ServerInfo();
        try
        {
            serverInfo.setAddress(InetAddress.getLocalHost());
        }
        catch (UnknownHostException uhe)
        {
            fireServerErrorEvent(new ServerEvent(this,
                    "Error retrieving Inet Address info for this machine\n"+uhe.getStackTrace()));


        }
        
        serverInfo.setCurrentConnections(0);
        fireServerInfoUpdatedEvent(new ServerEvent(this, "Initial Server Info Created"));
    }

    public void registerServerListener(ServerListener l)
    {
        listeners.add(l);
    }
    private void fireHostedFilesUpdatedEvent(ServerEvent e){
        for(ServerListener l : listeners)
        {
            l.hostedFilesUpdatedEvent(e);
        }
    }
    private void fireServerErrorEvent (ServerEvent e) {
        for(ServerListener l : listeners)
        {
            l.serverErrorEvent(e);
        }
    }
    private  void fireServerInfoUpdatedEvent(ServerEvent e){
        for(ServerListener l : listeners)
        {
            l.serverInfoUpdatedEvent(e);
        }
    }
    public void FileReceived(FileInfo info, byte[] bytes)
    {
        String fileName = info.getFileName();
        FileOutputStream fs = null;
        try {
            fs = new FileOutputStream(new File(serverConfig.getFileStorePath().getAbsolutePath() + "/" + info.getFileName()));
        } catch (FileNotFoundException ex) {
           fireServerErrorEvent(new ServerEvent(this, "couldn't write file: " + info.getFileName()));
        }
        if (fs!=null)
        {
            try {
                fs.write(bytes);
                fs.flush();
                fs.close();
                File fileToAdd = new File(serverConfig.getFileStorePath().getAbsolutePath()+"/" + info.getFileName());
                synchronized(hostedFileList)
                {
                    hostedFileList.add(fileToAdd);
                }
                
            } catch (IOException ex) {
                fireServerErrorEvent(new ServerEvent(this, "error writing file: " + info.getFileName()));
            }
        }
        hostedFilesUpdated();

    }
    public void NewConfigurationReceived(ServerEvent e, ServerConfiguration configuration) {
        boolean registrySuccess = false;
        try
        {
              Registry registry = LocateRegistry.getRegistry(configuration.getRegistryServer());
              picRegistry = (PicRegistry) registry.lookup("PicRegistry");
             
        }
        catch(RemoteException re)
        {
            ServerEvent reEvent = new ServerEvent(this, 
                    "Remote exception trying to connect to registry: " + re.getStackTrace());
            fireServerErrorEvent(reEvent);
        }
        catch(NotBoundException nbe)
        {
            ServerEvent nbeEvent = new ServerEvent(this, "Not Bound Exception: " + nbe.getStackTrace());
            fireServerErrorEvent(nbeEvent);
        }
        if (picRegistry != null)
        {
            serverInfo.setPort(configuration.getTcpListenerPort());
            
            monitor.setVisible(true);
            serverConfig = configuration;

            if (e.getSource() instanceof ConfigurationManager)
            {
                ConfigurationManager managerWindow = (ConfigurationManager) e.getSource();
                managerWindow.dispose();
            }
            File[] farray = retrieveFilesFromDir();
            hostedFileList.addAll(Arrays.asList(farray));
                     
            hostedFilesUpdated();
            tcpConnectionManager = new ConnectionManager(this, serverConfig.getTcpListenerPort(), 100);
            tcpConnectionManager.AddListener(monitor);
            connectionListenerThread = new Thread(tcpConnectionManager);
            connectionListenerThread.start();

        }
    }
    public InputStream getFileStream(String fileName) throws FileNotFoundException
    {
        InputStream stream  = new FileInputStream(new File(serverConfig.getFileStorePath().getAbsolutePath()+"/"+fileName));
        return stream;
    }
    public void hostedFilesUpdated()
    {
           initFileInfoList();
           synchronized(hostedFileList)
           {
                  if (serverInfo.getFileList().size() != hostedFileList.size())
                fireServerErrorEvent(new ServerEvent(this, "Inconsistent file lists are present in the server."));
           try
           {
                picRegistry.registerServer(serverInfo);
                ServerEvent fileRegistryUpdatedEvent = new ServerEvent(this,"Registry at " + serverConfig.getRegistryServer() + "successfully updated.");
           }
           catch (RemoteException ex)
           {
                ServerEvent reEvent = new ServerEvent(this,
                    "Couldn't call remote method registerServer(ServerInfo): " + ex.getMessage());
                fireServerErrorEvent(reEvent);
           }
           }
      
           ServerEvent fileListUpdatedEvent = new ServerEvent(this, "File List Updated Locally");
           fireHostedFilesUpdatedEvent(fileListUpdatedEvent);
    }
    public ServerConfiguration getConfig()
    {
        return serverConfig;
    }
    public void initFileInfoList()
    {
        List<FileInfo> fileInfoList = new ArrayList<FileInfo>();
        synchronized(hostedFileList)
        {
            for (File file : hostedFileList)
        {
            FileInfo info = null;
            try {
                info = new FileInfo(file);
            }catch (NoSuchAlgorithmException nse) {
                ServerEvent nsae = new ServerEvent(this, "Hashing error: " + nse.getStackTrace());
                fireServerErrorEvent(nsae);
            }
            catch (FileNotFoundException ex) {
                ServerEvent fnfEvent = new ServerEvent(this, file.getName()+" not found on local system: " + ex.getStackTrace());
                fireServerErrorEvent(fnfEvent);
            }
            if (info != null)
                fileInfoList.add(info);
        }
        }


        serverInfo.setFileList(fileInfoList);
    }
    public ServerInfo getServerInfo()
    {
        return serverInfo;
    }
    public List<File> getHostedFileList()
    {
        return hostedFileList;
    }
    private File[] retrieveFilesFromDir()
    {
       File[] fileArray = serverConfig.getFileStorePath().listFiles(new FileFilter(){
            public boolean accept(File pathname) {
                return pathname.isFile();
            }
       });
       return fileArray;
    }


}
